package com.ybl.store.backend.service.impl.item;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ybl.store.backend.dao.entity.item.VoucherDO;
import com.ybl.store.backend.dao.mapper.item.VoucherMapper;
import com.ybl.store.backend.dto.req.item.voucher.VoucherSaveReqDTO;
import com.ybl.store.backend.dto.req.item.voucher.VoucherUpdateReqDTO;
import com.ybl.store.backend.dto.resp.item.voucher.VoucherNameRespDTO;
import com.ybl.store.backend.service.item.VoucherService;
import com.ybl.store.common.constant.BanFlag;
import com.ybl.store.common.constant.DelFlag;
import com.ybl.store.common.convention.errorcode.BaseErrorCode;
import com.ybl.store.common.convention.exception.ClientException;
import com.ybl.store.common.entity.ListRespDTO;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.AbstractMap;
import java.util.List;
import java.util.Objects;

@Service
@RequiredArgsConstructor
@Transactional
public class VoucherServiceImpl extends ServiceImpl<VoucherMapper, VoucherDO> implements VoucherService {

    public static final Integer bitmapLength = 4000;

    public static final Integer prefixLength = 2;

    public static final Integer suffixLength = 4;

    @Override
    public void saveVoucher(VoucherSaveReqDTO requestParam) {
        VoucherDO voucherDO = BeanUtil.toBean(requestParam, VoucherDO.class);
//        voucherDO.setPrefix(createRandomPrefix());
//        voucherDO.setUsageBitmap(createBitmap());
//        voucherDO.setDistributionBitmap(createBitmap());
        int result = baseMapper.insert(voucherDO);
        if (result < 1) {
            throw new ClientException(BaseErrorCode.GIFT_SAVE_ERROR);
        }
    }

    @Override
    public void deleteVoucher(Long id) {
        int result = baseMapper.deleteById(id);
        if (result < 1) {
            throw new ClientException(BaseErrorCode.GIFT_DELETE_ERROR);
        }
    }

    @Override
    public void updateVoucher(VoucherUpdateReqDTO requestParam) {
        int result = baseMapper.updateById(BeanUtil.toBean(requestParam, VoucherDO.class));
        if (result < 1) {
            throw new ClientException(BaseErrorCode.GIFT_UPDATE_ERROR);
        }
    }

    @Override
    public void banVoucher(Long id, Integer banFlag) {
        VoucherDO voucherDO = new VoucherDO();
        voucherDO.setId(id);
        voucherDO.setBanFlag(banFlag);
        int result = baseMapper.updateById(voucherDO);
        if (result < 1) {
            throw new ClientException(BaseErrorCode.GIFT_BAN_ERROR);
        }
    }

    @Override
    public ListRespDTO<VoucherDO> pageVoucher(Integer pn, Integer ps, String name, String serial) {
        String prefix = null;
        if (serial != null) {
            AbstractMap.SimpleEntry<String, Integer> stringIntegerSimpleEntry = parseSerial(serial);
            prefix = stringIntegerSimpleEntry.getKey();
        }

        Page<VoucherDO> page = new Page<>(pn, ps);
        LambdaQueryWrapper<VoucherDO> lambdaQueryWrapper = Wrappers.lambdaQuery(VoucherDO.class)
//                .eq(Objects.nonNull(prefix), VoucherDO::getPrefix, prefix)
                .like(Objects.nonNull(name),VoucherDO::getName, name)
                .eq(VoucherDO::getDelFlag, DelFlag.present)
                .orderByAsc(VoucherDO::getName);
        Page<VoucherDO> voucherPage = baseMapper.selectPage(page, lambdaQueryWrapper);

        return ListRespDTO.<VoucherDO>builder()
                .total(voucherPage.getTotal())
                .items(voucherPage.getRecords())
                .build();
    }

    @Override
    public ListRespDTO<VoucherNameRespDTO> listVoucherName() {
        LambdaQueryWrapper<VoucherDO> lambdaQueryWrapper = Wrappers.lambdaQuery(VoucherDO.class)
                .eq(VoucherDO::getDelFlag, DelFlag.present)
                .eq(VoucherDO::getBanFlag, BanFlag.use)
                .orderByAsc(VoucherDO::getName);
        List<VoucherDO> voucherList = baseMapper.selectList(lambdaQueryWrapper);

        return ListRespDTO.<VoucherNameRespDTO>builder()
                .total((long) voucherList.size())
                .items(voucherList
                        .stream()
                        .map(each -> BeanUtil.toBean(each, VoucherNameRespDTO.class))
                        .toList())
                .build();
    }

    public void setUsageBitmap(String serial, Character value) {
        AbstractMap.SimpleEntry<String, Integer> stringIntegerSimpleEntry = parseSerial(serial);
        String prefix = stringIntegerSimpleEntry.getKey();
        Integer suffix = stringIntegerSimpleEntry.getValue();

        LambdaQueryWrapper<VoucherDO> lambdaQueryWrapper = Wrappers.lambdaQuery(VoucherDO.class)
//                .eq(VoucherDO::getPrefix, prefix)
                .eq(VoucherDO::getDelFlag, DelFlag.present)
                .eq(VoucherDO::getBanFlag, BanFlag.use);
        VoucherDO voucherDO = baseMapper.selectOne(lambdaQueryWrapper);
        if (voucherDO == null) {
            throw new ClientException(BaseErrorCode.VOUCHER_NULL_ERROR);
        }

//        StringBuilder usageBitmap = new StringBuilder(voucherDO.getUsageBitmap());
//        if (usageBitmap.charAt(suffix) == '1' && value == '1') {
//            throw new ClientException(BaseErrorCode.VOUCHER_USAGE_ERROR);
//        }
//        usageBitmap.setCharAt(suffix, value);
//        voucherDO.setUsageBitmap(usageBitmap.toString());
        int result = baseMapper.updateById(voucherDO);
        if (result < 1) {
            throw new ClientException(BaseErrorCode.VOUCHER_UPDATE_ERROR);
        }
    }

    public void setDistributionBitmap(String serial, Character value) {
        AbstractMap.SimpleEntry<String, Integer> stringIntegerSimpleEntry = parseSerial(serial);
        String prefix = stringIntegerSimpleEntry.getKey();
        Integer suffix = stringIntegerSimpleEntry.getValue();

        LambdaQueryWrapper<VoucherDO> lambdaQueryWrapper = Wrappers.lambdaQuery(VoucherDO.class)
//                .eq(VoucherDO::getPrefix, prefix)
                .eq(VoucherDO::getDelFlag, DelFlag.present)
                .eq(VoucherDO::getBanFlag, BanFlag.use);
        VoucherDO voucherDO = baseMapper.selectOne(lambdaQueryWrapper);
        if (voucherDO == null) {
            throw new ClientException(BaseErrorCode.VOUCHER_NULL_ERROR);
        }

//        StringBuilder distributionBitmap = new StringBuilder(voucherDO.getDistributionBitmap());
//        if (distributionBitmap.charAt(suffix) == '1' && value == '1') {
//            throw new ClientException(BaseErrorCode.VOUCHER_DISTRIBUTION_ERROR);
//        }
//        distributionBitmap.setCharAt(suffix, value);
//        voucherDO.setDistributionBitmap(distributionBitmap.toString());
        int result = baseMapper.updateById(voucherDO);
        if (result < 1) {
            throw new ClientException(BaseErrorCode.VOUCHER_UPDATE_ERROR);
        }
    }

    public static AbstractMap.SimpleEntry<String, Integer> parseSerial(String serial) {
        try {
            if (serial.length() != prefixLength + suffixLength) {
                throw new ClientException(BaseErrorCode.VOUCHER_NULL_ERROR);
            }
            String prefix = serial.substring(0, prefixLength);
            int suffix = Integer.parseInt(serial.substring(prefixLength, suffixLength + prefixLength));
            return new AbstractMap.SimpleEntry<>(prefix, suffix);
        } catch(Throwable ignore) {
            throw new ClientException(BaseErrorCode.VOUCHER_NULL_ERROR);
        }
    }

//    private String createRandomPrefix () {
//        for (int i = 0; i < 100; i++) {
//            String prefix = RandomUtil.randomString("ABCDEFGHIJKLMNOPQRSTUVWXYZ", prefixLength);
//            LambdaQueryWrapper<VoucherDO> lambdaQueryWrapper = Wrappers.lambdaQuery(VoucherDO.class)
//                    .eq(VoucherDO::getPrefix, prefix);
//            if (baseMapper.selectOne(lambdaQueryWrapper) == null) {
//                return prefix;
//            }
//        }
//        throw new ClientException(BaseErrorCode.VOUCHER_SAVE_ERROR);
//    }

    private String createBitmap() {
        return "0".repeat(bitmapLength);
    }
}
